<template>
  <div>
    <!-- <h1>SPU管理</h1> -->
    <!-- 此处是显示“三级分类下拉菜单”的页面结构↓ -->
    <Category
      :aVariableUsedToControlWhichDivElementUnderTheElCardComponentShouldBeShown="aVariableUsedToControlWhichDivElementUnderTheElCardComponentShouldBeShown" />
    <el-card style="margin: 0px 10px;">
      <!-- 注：此处不使用“v-if”，而使用“v-show”来控制“这个div元素是否需要被显示”，原因是“v-if在切换时的性能开销大”（因为它会在切换时销毁和加载组件），而“v-show”在“初次加载组件”时性能开销大，但在切换时的性能开销较小（因为用它做切换时只涉及在CSS层面是否添加样式规则“display:none;”）↓ -->
      <div v-show="aVariableUsedToControlWhichDivElementUnderTheElCardComponentShouldBeShown == 'aDivElementIncludeTable'">
        <el-button type="primary" size="default" icon="Plus"
          :disabled="categoryStore.idOfCategory3 ? false : true" @click="handlerForUserClickAddSpuButton" v-haveThisButton="`btn.Spu.add`">添加SPU</el-button>
        <!-- 展示已有SPU的数据↓ -->
        <el-table border style="margin: 10px 0px;" :data="anArrayThatStoresTheDataOfSpuThatHaveBeenHad">
          <el-table-column type="index" label="序号" width="80px" align="center"></el-table-column>
          <el-table-column label="SPU名称" align="center" width="120px" prop="spuName"></el-table-column>
          <!-- 注：属性“show-overflow-tooltip”的作用是“当单元格中的内容过长时，隐藏超出的内容，并在鼠标光标在单元格上悬停时，使用tooltip（提示条）来显示它们”↓ -->
          <el-table-column label="SPU描述" align="center" prop="description" show-overflow-tooltip></el-table-column>
          <el-table-column label="操作" width="250px" align="center">
            <!-- 注：此处的“row”就是“与当前鼠标光标所在行对应的已有的SPU对象”↓ -->
            <template #default="{ row, $index }">
              <el-button type="primary" size="small" icon="Plus" title="添加SKU" @click="handlerForUserClickAddSkuButton(row)" v-haveThisButton="`btn.Spu.addsku`"></el-button>
              <el-button type="warning" size="small" icon="Edit" @click="handlerForUserClickUpdateSpuButton(row)" title="修改SPU" v-haveThisButton="`btn.Spu.update`"></el-button>
              <el-button type="info" size="small" icon="View" title="查看SKU列表" @click="handlerForUserClickTheShowSkuListButton(row)" v-haveThisButton="`btn.Spu.skus`"></el-button>
              <el-popconfirm :title="`你确定删除${row.spuName}吗？`" width="200px" >
                <template #reference>
                  <el-button type="danger" size="small" icon="Delete" title="删除SPU" v-haveThisButton="`btn.Spu.delete`"></el-button>
                </template>
              </el-popconfirm>
            </template>
          </el-table-column>
        </el-table>
        <!-- 下面是分页器组件↓ -->
        <el-pagination @current-change="getAllOfTheSpuThatBelongsToASpecificCategory3" @size-change="handlerForchangeThePageSizeOfPaginationComponent"
          v-model:current-page="currentPageNumber" v-model:page-size="currentPageSize" :page-sizes="[3, 5, 7, 9]"
          :background="true" layout="prev, pager, next, jumper,->,sizes,total" :total="totalNumberOfTheSpuThatBelongsToASpecificCategory3" />
      </div>
      <!-- 添加或修改SPU时用到的子组件↓ -->
      <SpuForm ref="spuForm" v-show="aVariableUsedToControlWhichDivElementUnderTheElCardComponentShouldBeShown == 'aDivElementIncludeAFormThatBeUsedToAddOrEditSpu'" @changeScene="handlerForChangeSence"/>
      <!-- 添加SKU时用到的子组件↓ -->
      <SkuForm ref="skuForm" v-show="aVariableUsedToControlWhichDivElementUnderTheElCardComponentShouldBeShown == 'aDivElementIncludeAFormThatBeUsedToAddSku'" @changeScene="handlerForChangeSence"/>
      <!-- 展示SKU列表时用到的对话框组件↓ -->
      <el-dialog title="SKU列表" v-model="isTheDialogVisible">
        <!-- 123 -->
         <el-table border :data="skuList">
          <el-table-column label="SKU名称" prop="skuName" align="center"></el-table-column>
          <el-table-column label="SKU价格" prop="price" align="center"></el-table-column>
          <el-table-column label="SKU重量" prop="weight" align="center"></el-table-column>
          <el-table-column label="SKU图片" align="center">
            <template #default="{row,$index}">
              <img :src="row.skuDefaultImg" alt="图片地址已失效" style="width: 100px;height:100px;"/>
            </template>
          </el-table-column>
         </el-table>
      </el-dialog>
    </el-card>
  </div>
</template>

<script lang="ts" setup name="SPU">
import { ref, watch,onBeforeUnmount } from 'vue'
// 导入并获取涉及到“三级分类”的仓库↓
import useCategoryStore from '@/store/modules/category'
import { requestSpuThatHaveBeenHad,requestTheSkuListUnderAnExistingSpu,requestDeleteAnExistingSpu } from "@/api/product/spu"
import { ElMessage } from "element-plus"
// 导入子组件↓
import SpuForm from "./spuForm.vue"
import SkuForm from "./skuForm.vue"
import type { typeOfResponseDataOfTheApiThatGetsSpusThatHaveBeenHad, typeOfPropertyNamedRecordsInTheResponseDataOfTheApiThatGetsSpusThatHaveBeenHad,typeOfObjectThatRepresentsAnSpu,typeOfResponseDataOfTheApiThatGetsSkuData,typeOfObjectThatRepresentsAnSku } from "@/api/product/spu/type"
let categoryStore = useCategoryStore()
// 监听三级分类的id的变化↓
watch(() => categoryStore.idOfCategory3, () => {
  // 注：进入此代码块，说明三级分类的ID已经发生了变化，且是有效的，服务器已经返回了该三级分类下的所有SPU的数据。但是为了防止用户点击三级分类项后又重新点击一、二级分类的下拉菜单，重新选择一/二级分类，导致三级分类的ID丢失，发送无效请求，所以需要保证在“有三级分类ID”的情况下才能发送请求↓
  if (!categoryStore.idOfCategory3) {
    return // 如果没有三级分类的ID，则直接返回,退出函数执行流程
  } else {
    getAllOfTheSpuThatBelongsToASpecificCategory3()
  }
})
let isTheDialogVisible = ref<boolean>(false) // 定义一个变量，它被用来控制对话框组件是否可见
// 定义一个变量，它被用来控制哪一个div元素应该在el-card组件下显示↓
let aVariableUsedToControlWhichDivElementUnderTheElCardComponentShouldBeShown = ref<string>("aDivElementIncludeTable") // 默认显示被用于展示已有的SPU的表格所在的div元素
// let aVariableUsedToControlWhichDivElementUnderTheElCardComponentShouldBeShown = ref<string>("aDivElementIncludeAFormThatBeUsedToAddOrEditSpu")
let currentPageNumber = ref<number>(1)
// 分页器每页显示的条目数↓
let currentPageSize = ref<number>(3)
// 定义一个数组，它被用来存储已经被获取到的SPU的数据↓
let anArrayThatStoresTheDataOfSpuThatHaveBeenHad = ref<typeOfPropertyNamedRecordsInTheResponseDataOfTheApiThatGetsSpusThatHaveBeenHad>([])
let skuList = ref<typeOfObjectThatRepresentsAnSku[]>([]) // 定义一个变量，它被用来存储某个SPU下的SKU列表
// 定义一个变量，它被用来存储属于某个三级分类的SPU的总数↓
let totalNumberOfTheSpuThatBelongsToASpecificCategory3 = ref<number>(0)
let spuForm = ref<any>() // 定义一个变量，它被用于获取子组件“spuForm”的实例，以便调用子组件内部的方法（注：该变量必须与“ref标记”同名）
let skuForm = ref<any>() // 定义一个变量，它被用于获取子组件“skuForm”的实例，以便调用子组件内部的方法
/* 注：以下内容是“文心快码”对“为什么使用ref获取组件实例时，声明的变量必须与ref标记同名”的解释：
在Vue 3中，ref获取子组件实例的命名规则：1.分析与思考：在Vue 3中，ref 是一个用于在模板中注册引用信息的API。当我们在模板中使用 ref 属性时，Vue 会将对应的 DOM 元素或子组件实例存储在一个响应式对象中，该对象的键是我们在模板中定义的 ref 名称。
问题的关键在于理解 ref 的工作原理以及 Vue 是如何管理和访问这些引用信息的。Vue 通过模板中定义的 ref 名称来存储和检索对应的元素或组件实例。如果声明的变量名与 ref 标记不同名，Vue 将无法正确地将引用信息与变量关联起来，从而导致无法通过变量访问到对应的子组件实例。
2.回答：a.ref 的工作原理：在 Vue 3 的模板中，ref 用于注册一个引用信息。这个引用可以是一个 DOM 元素，也可以是一个子组件实例。当 Vue 渲染模板时，它会检查所有带有 ref 属性的元素或组件，并将它们存储在一个内部对象中。这个对象的键是 ref 的名称，值是对应的元素或组件实例。
b.为什么声明的变量必须与“ref标记”同名：Vue 通过 ref 名称来关联模板中的元素或组件实例与组件逻辑中的变量。如果声明的变量名与 ref 标记不同名，Vue 将无法将引用信息与变量正确关联。这意味着在组件的逻辑中，您将无法通过变量访问到对应的子组件实例。因此，为了确保能够正确地访问子组件实例，声明的变量名必须与模板中的 ref 标记同名。↑ */
/**
 * 函数“getAllOfTheSpuThatBelongsToASpecificCategory3”被用来获取属于某个三级分类的所有SPU
 */
// 在调用函数且“未传参”的情况下，使用默认值——“1”（注：用户在分页器上选择页码时，页码会被自动作为参数传入此函数）↓
async function getAllOfTheSpuThatBelongsToASpecificCategory3(pageNumber = 1) {
  currentPageNumber.value = pageNumber // 更新当前页码数
  let result: typeOfResponseDataOfTheApiThatGetsSpusThatHaveBeenHad = await requestSpuThatHaveBeenHad(currentPageNumber.value, currentPageSize.value, categoryStore.idOfCategory3)
  // 注：不知何故，从“chrome浏览器”的“开发者工具”的“网络”选项卡中，我看到服务器已经返回了响应的数据（内容是“{code: 200, message: "成功", data: {,…}, ok: true}”），但是针对“result”，控制台中打印出来的结果却是“undefined”↓
  // console.log(result) // undefined（控制台中输出“undefined”原因已查明：开发者未在定义接口方法处使用“async...await”结构，而后台服务器现在又有问题，导致接口方法调用“get”方法时直接返回了Promise自身，导致该Promise未被解析，也就拿不到服务器返回的数据）
  console.log(result) // {code: 200, message: '成功', data: {…}, ok: true}
  if (result.code == 200) {
    anArrayThatStoresTheDataOfSpuThatHaveBeenHad.value = result.data.records // 把数据赋值给被用于存储已有的SPU的数据的数组
    totalNumberOfTheSpuThatBelongsToASpecificCategory3.value = result.data.total // 把总数赋值给被用于存储总数的变量

  } else {
    ElMessage({
      type: "error",
      // message: "获取数据失败",
      message: result.message,
    })
    return false;
  }
}
/**
 * 函数“handlerForchangeThePageSizeOfPaginationComponent”被用来处理“分页器每页显示的条目数发生变化”时的事件
 */
function handlerForchangeThePageSizeOfPaginationComponent() {
  getAllOfTheSpuThatBelongsToASpecificCategory3() // 重新获取数据（注：获取的数据是第一页的数据（因为没有传参））
}
/**
 * 函数“handlerForUserClickAddSpuButton”被用来处理用户点击添加SPU按钮时的事件
 */
function handlerForUserClickAddSpuButton() {
  aVariableUsedToControlWhichDivElementUnderTheElCardComponentShouldBeShown.value = "aDivElementIncludeAFormThatBeUsedToAddOrEditSpu" // 显示被用于添加或修改SPU的表单所在的div元素
  spuForm.value.initDataOfTheSpuThatBeAdded(categoryStore.idOfCategory3) // 调用子组件的方法，以便初始化表单的数据（注：该方法在子组件中被定义为“initDataOfTheSpuThatBeAdded”）

}
/**
 * 函数“handlerForUserClickUpdateSpuButton”被用来处理用户点击修改SPU按钮时的事件
 */
function handlerForUserClickUpdateSpuButton(row: typeOfObjectThatRepresentsAnSpu) {
  aVariableUsedToControlWhichDivElementUnderTheElCardComponentShouldBeShown.value = "aDivElementIncludeAFormThatBeUsedToAddOrEditSpu"
  console.log(spuForm.value) // 打印子组件的实例（控制台输出：Proxy(Object) {__v_skip: true}）
  spuForm.value.initDataOfTheSpuThatHaveBeenHad(row) // 调用子组件的方法，以便初始化表单的数据（注：该方法在子组件中被定义为“initDataOfTheSpuThatHaveBeenHad”）

}
/**
 * 函数“handlerForChangeSence”被用来处理子组件（即：表单）向父组件传递的自定义事件
 */
// function handlerForChangeSence(payload: string) { // payload（载荷）是一个字符串，由子组件触发自定义事件时提交，它被用来控制哪一个div元素应该在el-card组件下显示
function handlerForChangeSence(object:any) {
  console.log(object)
  console.log(object.flag,object.params)
  // aVariableUsedToControlWhichDivElementUnderTheElCardComponentShouldBeShown.value = payload // 更新变量，以便显示被用于展示已有的SPU的表格所在的div元素
  aVariableUsedToControlWhichDivElementUnderTheElCardComponentShouldBeShown.value = object.flag
  if (object.params == "updateSpu") {
    getAllOfTheSpuThatBelongsToASpecificCategory3(currentPageNumber.value) // 重新获取数据（注：获取的数据是当前页的数据（因为传入了参数））
  } else {
    getAllOfTheSpuThatBelongsToASpecificCategory3() // 重新获取数据（注：获取的数据是第一页的数据（因为没有传参））
  }
}
/**
 * @description 函数“handlerForUserClickAddSkuButton”被用来处理用户点击添加SKU按钮时发生的事件
 */
function handlerForUserClickAddSkuButton(row: typeOfObjectThatRepresentsAnSpu) {
  aVariableUsedToControlWhichDivElementUnderTheElCardComponentShouldBeShown.value = "aDivElementIncludeAFormThatBeUsedToAddSku" // 显示被用于添加SKU的表单所在的div元素
  console.log(row)
  skuForm.value.initDataOfTheSku(categoryStore.idOfCategory1,categoryStore.idOfCategory2,row) // 调用子组件内部的方法，以便初始化表单的数据
}
/**
 * @description 函数“handlerForUserClickTheShowSkuListButton”被用来处理用户点击展示SKU列表按钮时发生的事件
 * @param row 被用来传递SPU对象，以便获取属于该SPU的SKU列表
 */
async function handlerForUserClickTheShowSkuListButton(row: typeOfObjectThatRepresentsAnSpu) {
  let result:typeOfResponseDataOfTheApiThatGetsSkuData = await requestTheSkuListUnderAnExistingSpu((row.id as number)) // 调用函数，以便获取属于该SPU的SKU列表
 if (result.code == 200) {
  skuList.value = result.data // 把数据赋值给被用于存储SKU列表的变量
  isTheDialogVisible.value = true // 显示对话框组件
 }
}
/**
 * @description 函数“handlerForUserClickTheDeleteSpuButton”被用来处理用户点击删除SPU按钮时发生的事件
 * @param row 参数“row”被用来传递SPU对象，以便删除该SPU
 */
async function handlerForUserClickTheDeleteSpuButton(row: typeOfObjectThatRepresentsAnSpu) {
  let result:any = await requestDeleteAnExistingSpu((row.id as number)) // 调用函数，以便删除SPU
  if (result.code == 200) {
    ElMessage({
      type: "success",
      message: "删除成功",
    })
    // 获取剩余的SPU数据。如果删除这个SPU后，剩余的SPU数量不足以填满当前页，则应该显示上一页的数据↓
    getAllOfTheSpuThatBelongsToASpecificCategory3(anArrayThatStoresTheDataOfSpuThatHaveBeenHad.value.length>1?currentPageNumber.value:currentPageNumber.value-1)
  } else {
    ElMessage({
      type: "error",
      message: "删除失败",
    })
    
  }
}
// 在每次组件被销毁之前，清除仓库中涉及到“分类”的数据↓
onBeforeUnmount(() => {
  categoryStore.$reset()
})
</script>

<style scoped></style>